package com.gdut.huayan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gdut.huayan.constant.SecurityConstant;
import com.gdut.huayan.dao.*;
import com.gdut.huayan.entity.dto.PageQuery;
import com.gdut.huayan.entity.po.*;
import com.gdut.huayan.entity.vo.ActivityStockVo;
import com.gdut.huayan.entity.vo.ActivityVo;
import com.gdut.huayan.entity.vo.FestivalVo;
import com.gdut.huayan.entity.vo.StockVo;
import com.gdut.huayan.service.FestivalService;
import com.gdut.huayan.service.FileService;
import com.gdut.huayan.service.exception.BaseException;
import com.gdut.huayan.utils.AliyunUtils;
import com.gdut.huayan.utils.SecurityUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FestivalServiceImpl extends ServiceImpl<FestivalMapper, Festival> implements FestivalService {

    @Autowired
    private LocationMapper locationMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private LimitNameMapper limitNameMapper;

    @Autowired
    private StockMapper stockMapper;

    @Autowired
    private MoneyStockMapper moneyStockMapper;
    @Autowired
    private LimitMoneyMapper limitMoneyMapper;

    @Autowired
    private FileService fileService;


    @Override
    public Map<String, String> getUploadLink() {
        Map<String, String> result = new HashMap<>();
        long now = new Date().getTime();
        String filePath = "festival/" + UUID.randomUUID() + now + ".jpeg";
        String uploadLink = AliyunUtils.getUploadLink(filePath, "image/jpeg", now + SecurityConstant.TIME_TEN_MINUTES);
        result.put("filePath", filePath);
        result.put("uploadLink", uploadLink);
        return result;
    }

    @Override
    public boolean save(Festival entity) {
        if (entity.getStartTime().isAfter(entity.getEndTime())){
            throw new BaseException(4000,"开始时间不能大于结束时间");
        }
        entity.setCreateUser(SecurityUtils.getUserIdNumber());
        return super.save(entity);
    }


    @Override
    public PageInfo<Festival> getPage(PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPage(), pageQuery.getSize());
        QueryWrapper<Festival> wrapper = new QueryWrapper<>();
        wrapper.like("main_title", "%" + pageQuery.getSearch() + "%");
        if ("ASC".equals(pageQuery.getOrder())) {
            wrapper.orderByAsc(pageQuery.getOrderKey().split(";"));
        }
        if ("DESC".equals(pageQuery.getOrder())) {
            wrapper.orderByDesc(pageQuery.getOrderKey().split(";"));
        }
        return new PageInfo<>(baseMapper.selectList(wrapper));
    }

    @Override
    public List<Festival> get() {
        return new LambdaQueryChainWrapper<>(baseMapper)
                .le(Festival::getStartTime, LocalDateTime.now())
                .ge(Festival::getEndTime, LocalDateTime.now()).list();
    }

    @Override
    public List<FestivalVo> get(Long festivalId) {
        QueryWrapper<Stock> queryStock = new QueryWrapper<>();
        queryStock.eq("festival_id", festivalId);
        List<Stock> stockList = stockMapper.selectList(queryStock);
        if (stockList.isEmpty()) {
            throw new BaseException(4000, "该节日下暂无更多节点");
        }
        List<Long> stockIdList = new ArrayList<>();
        Set<Long> removalLocationId = new HashSet<>();
        Set<Long> removalActivityId = new HashSet<>();
        for (Stock stock : stockList) {
            stockIdList.add(stock.getId());
            removalLocationId.add(stock.getLocationId());
            removalActivityId.add(stock.getActivityId());
        }
        List<Location> locationList = locationMapper.selectBatchIds(removalLocationId);
        List<Activity> activityList = activityMapper.selectBatchIds(removalActivityId);
        QueryWrapper<LimitName> nameQuery = new QueryWrapper<>();
        nameQuery.in("activity_id", removalActivityId);
        List<LimitName> nameList = limitNameMapper.selectList(nameQuery);
        QueryWrapper<MoneyStock> moneyStockQuery = new QueryWrapper<>();
        moneyStockQuery.in("stock_id", stockIdList);
        List<MoneyStock> moneyStockList = moneyStockMapper.selectList(moneyStockQuery);
        Set<Long> moneyIdList = new HashSet<>();
        moneyStockList.forEach(m -> {
            moneyIdList.add(m.getLimitMoneyId());
        });

        boolean moneyFlag = !moneyIdList.isEmpty();
        Map<Long, LimitMoney> hashMoney = null;
        Map<Long, List<MoneyStock>> hashMS = null;
        if (moneyFlag) {
            hashMoney = limitMoneyMapper.selectBatchIds(moneyIdList).stream().collect(Collectors.toMap(LimitMoney::getId, limitMoney -> limitMoney));
            hashMS = moneyStockList.stream().collect(Collectors.groupingBy(MoneyStock::getStockId));
        }
        Map<Long, Activity> hashActivity = activityList.stream().collect(Collectors.toMap(Activity::getId, activity -> activity));
        Map<Long, Location> hashLocation = locationList.stream().collect(Collectors.toMap(Location::getId, location -> location));
        Map<Long, List<LimitName>> hashName = nameList.stream().collect(Collectors.groupingBy(LimitName::getActivityId));

        Map<Long, FestivalVo> hashFestivalVo = new HashMap<>();
        Map<Long, Map<Long, ActivityStockVo>> hashActivityStockVo = new HashMap<>();
        for (Stock stock : stockList) {
            StockVo stockVo = new StockVo(stock, new ArrayList<>());
            if (moneyFlag) {
                List<MoneyStock> tempMS = hashMS.get(stock.getId());
                if(tempMS != null){
                    for (MoneyStock MS : tempMS) {
                        stockVo.getLimitMoneyList().add(hashMoney.get(MS.getLimitMoneyId()));
                    }
                }
            }
            if (!hashFestivalVo.containsKey(stock.getLocationId())) {
                FestivalVo festivalVo = new FestivalVo();
                festivalVo.setActivityStockList(new ArrayList<>());
                festivalVo.setLocation(hashLocation.get(stock.getLocationId()));
                hashFestivalVo.put(stock.getLocationId(), festivalVo);
            }

            if (hashActivityStockVo.containsKey(stock.getLocationId())) {
                Map<Long, ActivityStockVo> longActivityStockVoMap = hashActivityStockVo.get(stock.getLocationId());
                if (!longActivityStockVoMap.containsKey(stock.getActivityId())) {
                    ActivityVo activityVo = new ActivityVo(hashActivity.get(stock.getActivityId()), hashName.get(stock.getActivityId()));
                    hashActivityStockVo.get(stock.getLocationId()).put(stock.getActivityId(), new ActivityStockVo(activityVo, new ArrayList<>()));
                }
            } else {
                ActivityVo activityVo = new ActivityVo(hashActivity.get(stock.getActivityId()), hashName.get(stock.getActivityId()));
                Map<Long, ActivityStockVo> tempMap = new HashMap<>();
                tempMap.put(stock.getActivityId(), new ActivityStockVo(activityVo, new ArrayList<>()));
                hashActivityStockVo.put(stock.getLocationId(), tempMap);
            }
            hashActivityStockVo.get(stock.getLocationId()).get(stock.getActivityId()).getStockVoList().add(stockVo);
        }
        for (Long locationId : hashFestivalVo.keySet()) {
            hashFestivalVo.get(locationId).setActivityStockList(new ArrayList<>(hashActivityStockVo.get(locationId).values()));
        }
        return new ArrayList<>(hashFestivalVo.values());
    }

    @Override
    public boolean removeById(Serializable id) {
        if (isCanOperation(id)) {
            throw new BaseException(4000, "不允许删除正在使用中的法会");
        }
        Festival deleteFestival = baseMapper.selectById(id);
        if (deleteFestival == null) {
            return true;
        }
        return super.removeById(id);
    }

    @Override
    public boolean updateById(Festival festival) {
        festival.setCreateUser(null);
        if (festival.getStartTime() != null && festival.getEndTime() != null && festival.getStartTime().isAfter(festival.getEndTime())){
            throw new BaseException(4000,"开始时间不能大于结束时间");
        }
        festival.setBackgroundFileId(null);
        festival.setCoverFileId(null);
        return super.updateById(festival);
    }

    private boolean isCanOperation(Serializable id) {
        QueryWrapper<Stock> wrapper = new QueryWrapper<>();
        wrapper.eq("festival_id", id);
        int count = stockMapper.selectCount(wrapper);
        return count != 0;
    }

}
